package com.ciaojian.worker.controller;

import cn.hutool.core.util.RandomUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ciaojian.core.enums.business.OrderOrderTypeEnum;
import com.ciaojian.core.enums.business.OrderStatusEnum;
import com.ciaojian.core.enums.business.PayTypeEnum;
import com.ciaojian.core.model.HaloDetail;
import com.ciaojian.core.model.Order;
import com.ciaojian.core.util.BigDecimalUtil;
import com.ciaojian.core.util.Result;
import com.ciaojian.core.util.StringUtil;
import com.ciaojian.core.util.TokenUtil;
import com.ciaojian.pay.alipay.AliPayApi;
import com.ciaojian.pay.alipay.AliPayApiConfig;
import com.ciaojian.pay.alipay.AliPayBean;
import com.ciaojian.pay.core.enums.SignType;
import com.ciaojian.pay.core.kit.WxPayKit;
import com.ciaojian.pay.wxpay.WxPayApi;
import com.ciaojian.pay.wxpay.model.request.UnifiedOrderModel;
import com.ciaojian.pay.wxpay.model.response.NotifyResponse;
import com.ciaojian.pay.wxpay.model.response.UnifiedOrderModelResponse;
import com.ciaojian.worker.pay.WxPayBean;
import com.ciaojian.worker.service.OrderServiceImpl;
import io.swagger.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;

/**
 * @author Atlakyn
 */
@Api(tags = "支付接口")
@RequestMapping("/pay")
@RestController
public class PayController {
    private static final Logger payLog = LoggerFactory.getLogger("pay");
    private static final Logger exLog = LoggerFactory.getLogger("exception");

    @Resource
    private WxPayBean wxPayBean;
    @Resource
    private OrderServiceImpl orderService;
    @Resource
    private AliPayBean aliPayBean;

    @ApiOperation("Halo 支付")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "orderId", value = "订单Id", paramType = "query"),
            @ApiImplicitParam(name = "haloDetailId", value = "Halo Id", paramType = "query")
    })
    @PostMapping("/halo")
    public Result haloPay(@NotNull(message = "请选择订单") Integer orderId,
                          @NotNull(message = "请选择Halo券") Integer haloDetailId) {
        Order order = new Order().selectById(orderId);
        Assert.notNull(order, "订单不存在");

        HaloDetail haloDetail = new HaloDetail().selectById(haloDetailId);
        Assert.notNull(haloDetail, "Halo 券不存在");

        order.setPayTotal(new BigDecimal(haloDetail.getPrice()).divide(BigDecimalUtil.HUNDRED, 2, RoundingMode.HALF_UP));
        order.setPayType(PayTypeEnum.HALO_PAY.getDescription());
        order.setOrderType(OrderOrderTypeEnum.NORMAL);
        return Result.save(orderService.completeOrder(order));
    }

    @ApiOperation("现金支付")
    @PostMapping("/cash")
    public Result cashPay(@ApiParam("订单id") Integer orderId, HttpServletRequest request) throws IllegalAccessException {
        Assert.notNull(orderId, "请选择订单");
        Order order = new Order().selectById(orderId);
        Assert.notNull(order, "订单不存在");
        Assert.isTrue(order.getStatus().equals(OrderStatusEnum.servicing) || order.getStatus().equals(OrderStatusEnum.wait_pay), "订单已付款");
        Assert.isTrue(order.getOrderType().equals(OrderOrderTypeEnum.NORMAL), "不是剪发订单");

        String newOrderNo = orderService.generateOrderNoByOrderId(order.getId());
        payLog.info(">>>wxPay>>>新订单号={},旧订单号={}", newOrderNo, order.getOrderNo());
        // 修改订单号
        order.setOrderNo(newOrderNo);
        order.updateById();

        String token = request.getHeader("token");
        String openid = TokenUtil.getUserOpenid(token);

        Map<String, Object> params = UnifiedOrderModel
                .builder()
                .appid(wxPayBean.getAppId())
                .mch_id(wxPayBean.getMchId())
                .nonce_str(RandomUtil.randomString(32))
                .body(order.getStoreName().concat("-").concat(order.getType()))
                .out_trade_no(newOrderNo)
                .total_fee(String.valueOf(BigDecimalUtil.increase(order.getGoodsTotal(), BigDecimalUtil.HUNDRED, 0)))
                .spbill_create_ip(StringUtil.getIpAddr(request))
                .notify_url(wxPayBean.getDomain().concat("/worker/pay/cash/notify"))
                .trade_type(wxPayBean.getTradeType())
                .openid(openid)
                .build()
                .createSign(wxPayBean.getKey(), SignType.MD5);
        payLog.info(">>>购买优惠券支付方法>>>请求参数:{params:{}}", params);
        // 返回 xml 格式表单
        String xmlResult = WxPayApi.pushOrder(params);
        UnifiedOrderModelResponse response = WxPayKit.xmlToBean(xmlResult, UnifiedOrderModelResponse.class);
        payLog.info(">>>购买会员卡支付方法,支付请求返回参数={}>>>", response.toString());
        // 请求失败
        WxPayKit.codeIsOk(response);
        // 微信支付返回的预支付id
        String prepayLoggerId = response.getPrepay_id();
        // 二次签名，构建公众号唤起支付的参数,这里的签名方式要与上面统一下单请求签名方式保持一致
        Map<String, Object> packageParams = WxPayKit.miniAppPrepayIdCreateSign(
                wxPayBean.getAppId(),
                prepayLoggerId,
                wxPayBean.getKey(),
                SignType.MD5);
        // 将二次签名构建的数据返回给前端并唤起小程序支付
        return Result.ok(packageParams);
    }


    @ApiOperation("支付宝支付")
    @PostMapping("/ali")
    public Result aliPay() {
        AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
        model.setOutTradeNo("123456789");
        model.setTotalAmount("0.01");
        model.setSubject("剪发");

        AliPayApiConfig config = AliPayApiConfig
                .builder(aliPayBean);
        try {
            AlipayTradePrecreateResponse response = AliPayApi.tradePrecreatePayToResponse(model, aliPayBean.getDomain().concat("/worker/pay/ali/notify"), config);
            return Result.ok(response);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            exLog.error(e.getMessage());
            return Result.error("支付异常");
        }
    }

    @ApiOperation("支付宝支付回调")
    @PostMapping("/ali/notify")
    public void aliNotify(HttpServletRequest request, HttpServletResponse response) {
        System.err.println("回调成功!");
    }

    /**
     * @param orderId 订单 id
     * @return 修改结果
     */
    @ApiOperation(value = "支付成功,修改状态为已支付-待回调", hidden = true)
    @PostMapping("/front-end/pay/success/{orderId}")
    public Result frontEndPaySuccess(@PathVariable Integer orderId) {
        payLog.info(">>>frontEndPaySuccess 支付订单id={}>>>", orderId);
        // 支付成功,锁单
        return Result.ok(orderService.lockOrder(orderId));
    }


    @ApiOperation(value = "现金支付微信回调通知", hidden = true)
    @PostMapping("/cash/notify")
    public void cashNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        // sb为微信返回的xml
        String notifyXml = sb.toString();
        NotifyResponse notifyResponse = WxPayKit.xmlToBean(notifyXml, NotifyResponse.class);
        payLog.info(">>>cashNotify 微信支付回调返回 notifyXml 信息>>>map={}", notifyResponse.toString());
        //获取商户系统内部订单号（即取号时生成的订单编号)
        String orderNo = notifyResponse.getOut_trade_no();
        payLog.info(">>>cashNotify 微信支付回调,订单号={}>>>", orderNo);
        // 获取订单
        QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("order_no", orderNo);
        Order order = new Order().selectOne(queryWrapper);
        payLog.info(">>>cashNotify 微信支付回调,订单={}>>>", order);
        // 订单不为空 且 状态是 已支付-待回调 或者 待支付
        if (order != null && order.getStatus().equals(OrderStatusEnum.wait_notify)) {
            // 商户系统对于支付结果通知的内容一定要做签名验证(目前没验证)
            // 并校验返回的订单金额是否与商户侧的订单金额一致
            if (notifyResponse.getTotal_fee().equals(String.valueOf(BigDecimalUtil.increase(order.getGoodsTotal(), BigDecimalUtil.HUNDRED, 0)))) {
                // 回调业务
                orderService.payNotify(order);
                // 通知微信回调成功
                notifyResponse.notifyWx(response);
            }
        }
    }
}
